package com.seng.resourcetycoon.gui.models;

import com.seng.resourcetycoon.core.enums.ResourceType;
import com.seng.resourcetycoon.core.enums.TowerState;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.Clock;
import java.util.UUID;

import static java.lang.Math.round;

public class ResourceTower {

    private static final double LEVEL_UP_COST_MULTIPLIER = 1.2; // 升级成本递增系数
    private static final double UPGRADE_MULTIPLIER_RESOURCE = 1.1; // 资源生成量升级系数
    public static final double UPGRADE_MULTIPLIER_RELOAD = -0.1; // 装载速度升级系数
    private static final BigDecimal SELL_BACK_RATIO = new BigDecimal("0.5"); // 出售价格相对于购买价格的比例

    private static final double MINIMUM_RESOURCE_GENERATION_INTERVAL = 0.1;

    private final String id;
    private final String name;
    private final ResourceType resourceType;
    private BigDecimal buyPrice;

    private final BigDecimal baseCost;
    private final double resourceAmountBase;//基礎每次生成资源的数量
    private final double reloadSpeedBase;
    private double resourceGenerationInterval; // 生成资源的时间间隔，单位秒
    private int resourceGenerationAmount;// 每次生成资源的数量
    private BigDecimal sellPrice;
    private int level = 1;
    private int currentResourceAmount;
    private long lastGeneratedTime;
    private TowerState state = TowerState.IDLE;
    private Clock clock;

    public ResourceTower(ResourceAttributes attributes) {
        clock = Clock.systemDefaultZone();
        this.name = attributes.getName();
        this.resourceType = attributes.getResourceType();
        this.baseCost = attributes.getBaseCost();
        this.resourceAmountBase = attributes.getResourceAmountBase();
        this.reloadSpeedBase = attributes.getReloadSpeedBase();
        this.level = 1; // 初始化等级为1
        this.id = UUID.randomUUID().toString();
        // Assign default values or generate them based on resource type and randomness
        calculatePropertiesBasedOnLevel();
    }

    private void calculatePropertiesBasedOnLevel() {
        if (level < 0) {
            throw new IllegalArgumentException("Level is out of valid range.");
        }

        int levelForCalculation = Math.max(level, 1);

        this.resourceGenerationAmount = calculateResourceGenerationAmount(levelForCalculation);
        this.resourceGenerationInterval = calculateResourceGenerationIntervalWithExternalValues(getReloadSpeedBase(),UPGRADE_MULTIPLIER_RELOAD,levelForCalculation);
        this.buyPrice = calculateBuyPrice(levelForCalculation);
        this.sellPrice = calculateSellPrice(this.buyPrice);
    }

    private int calculateResourceGenerationAmount(int levelForCalculation) {
        return (int) round(resourceAmountBase * Math.pow(UPGRADE_MULTIPLIER_RESOURCE, levelForCalculation));
    }

    public double calculateResourceGenerationIntervalWithExternalValues(double reloadSpeedBase, double upgradeMultiplier, int level) {
        if (reloadSpeedBase <= 0) {
            throw new IllegalArgumentException("Reload speed base must be positive.");
        }

        double calculatedInterval = reloadSpeedBase * (1 + level * upgradeMultiplier);
        calculatedInterval = round(calculatedInterval * 10) / 10.0;
        return Math.max(calculatedInterval, MINIMUM_RESOURCE_GENERATION_INTERVAL);
    }

    private BigDecimal calculateBuyPrice(int levelForCalculation) {
        BigDecimal levelUpCostMultiplierPow = BigDecimal.valueOf(LEVEL_UP_COST_MULTIPLIER)
                .pow(levelForCalculation, MathContext.DECIMAL32);
        return baseCost.multiply(levelUpCostMultiplierPow)
                .setScale(0, RoundingMode.HALF_UP);
    }

    private BigDecimal calculateSellPrice(BigDecimal buyPrice) {
        return buyPrice.multiply(SELL_BACK_RATIO);
    }

    public void upgrade() {
        level++;
        calculatePropertiesBasedOnLevel();
    }

    /**
     * 根据当前时间和间隔判断是否应该生成资源，并执行生成操作。
     * 外部调用者应确保以适当的时间间隔调用此方法。
     */
    public boolean attemptToGenerateResources() {
        if (getState() != TowerState.ACTIVE) {
            return false;
        }
        long currentTime = getCurrentTimeMillis();
        if (currentTime - lastGeneratedTime >= (resourceGenerationInterval * 1000)) {
            currentResourceAmount += resourceGenerationAmount;
            lastGeneratedTime = getCurrentTimeMillis();
            return true;
        }
        return false;
    }

    private Long getCurrentTimeMillis(){
        return clock.millis();
    }

    public String getName() {
        return name;
    }

    public ResourceType getResourceType() {
        return resourceType;
    }


    public double getResourceGenerationInterval() {
        return resourceGenerationInterval;
    }

    public BigDecimal getBuyPrice() {
        return buyPrice;
    }


    public BigDecimal getSellPrice() {
        return sellPrice;
    }

    public int getLevel() {
        return level;
    }

    public int getCurrentResourceAmount() {
        return currentResourceAmount;
    }

    public void rest() {
        currentResourceAmount = 0;
    }

    public int getResourceGenerationAmount() {
        return resourceGenerationAmount;
    }

    public TowerState getState() {
        return state;
    }

    public void setState(TowerState state) {
        this.state = state;
    }

    public String getId() {
        return id;
    }

    public void setClock(Clock clock) {
        this.clock = clock;
    }

    public void setLastGeneratedTime(long l) {
        this.lastGeneratedTime = l;
    }

    public double getReloadSpeedBase() {
        return reloadSpeedBase;
    }
}
